/* Copyright (C) 2008-2009 by Giuseppe Pitta (Darkman) <darkman@darkman.it>
 * 
 * EaZy Psotnic Project
 */
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Collections;
using System.IO;
using Psotnic;

namespace Psotnic
{
    public enum SetsType
    {
        Bool,
        Combo,
        Time,
        Perc,
        Text
    }

    public class Session
    {
        private Hashtable settings;
        private Hashtable globalInfos;
        private Hashtable channels;
        private Hashtable users;
        private Hashtable bots;
        private String sName;

        public Boolean setsRequested = false;
        public Boolean channelsRequested = false;
        public Boolean usersRequested = false;
        public Boolean botsRequested = false;

        public Session(String sName)
        {
            settings = new Hashtable();
            globalInfos = new Hashtable();
            channels = new Hashtable();
            users = new Hashtable();
            bots = new Hashtable();
            this.sName = sName;
        }

        public String SessionName
        {
            get { return sName; }
        }

        public Boolean modSetting(String Setting, String Value)
        {
            return HashUtil.modHashtable(settings, Setting, Value);
        }

        public Boolean modGlobalInfo(String GlobalInfo, String Value)
        {
            return HashUtil.modHashtable(globalInfos, GlobalInfo, Value);
        }

        public Boolean addChannel(String ChName)
        {
            try
            {
                channels.Add(ChName, new Channel(ChName));
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public void delChannel(String ChName)
        {
            try
            {
                channels.Remove(ChName);
            }
            catch (Exception e) { }
        }

        public Boolean addUser(String handle)
        {
            try
            {
                users.Add(handle, new User(handle));
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

        public Boolean addHandle(String handle, Boolean isBot)
        {
            Hashtable ht;
            ht = isBot ? bots : users;
            if (ht.Contains(handle))
                return false;
            ht.Add(handle, isBot ? (Handle)new Bot(handle) : (Handle)new User(handle));
            return true;
        }

        public Handle getHandle(String handle, Boolean isBot)
        {
            Hashtable ht;
            ht = isBot ? bots : users;
            if (ht.Contains(handle))
                return (Handle)ht[handle];
            return null;
        }

        public Boolean delHandle(String handle, Boolean isBot)
        {
            Hashtable ht;
            ht = isBot ? bots : users;
            if (!ht.Contains(handle))
                return false;
            ht.Remove(handle);    
            return true;
        }

        public Hashtable getSettings()
        {
            return settings;
        }

        public Hashtable getChannels()
        {
            return channels;
        }

        public Hashtable getGlobalInfos()
        {
            return globalInfos;
        }

        public Hashtable getUsers()
        {
            return users;
        }

        public Hashtable getBots()
        {
            return bots;
        }

        public static int getIntValue(String spanString)
        {
            String[] tk;
            int mul = 1;
            int ret = 0;
            if (spanString == "INFINITY")
                return int.MaxValue;
            tk = spanString.Split(' ');
            foreach (String str in tk)
            {
                switch (str[str.Length - 1])
                {
                    case 'w':
                        mul = 60 * 60 * 24 * 7;
                        break;
                    case 'd':
                        mul = 60 * 60 * 24;
                        break;
                    case 'h':
                        mul = 60 * 60;
                        break;
                    case 'm':
                        mul = 60;
                        break;
                    default:
                        mul = 1;
                        break;
                }
                ret += int.Parse(str.TrimEnd(new char[] { 'w', 'd', 'h', 'm', 's', '%' })) * mul;
            }
            return ret;
        }

    }

    public class History
    {
        private ArrayList plHist;
        private int curHist;

        public History()
        {
            plHist = new ArrayList();
            curHist = 0;
        }

        public void addToHistory(String cmd)
        {
            plHist.Add(cmd);
            curHist = plHist.Count;
        }

        public String getPrev()
        {
            if (curHist > 0)
            {
                curHist--;
                return (String)plHist[curHist];
            }
            return null;
        }

        public String getNext()
        {
            if (curHist < plHist.Count)
            {
                curHist++;
                if (curHist == plHist.Count)
                    return "";
                else
                    return (String)plHist[curHist];
            }
            return null;
        }
    }

    public class Channel
    {
        private String ChName;
        private Hashtable ChSettings;
        private Hashtable Shits;
        private Hashtable Exempts;
        private Hashtable Reops;
        private Hashtable Invites;
        private List<Hashtable> Reibs;

        public enum ReibType : int
        {
            Shit = 0,
            Exempt = 1,
            Reop = 2,
            Invite = 3
        }

        public Channel(String ChName)
        {
            this.ChName = ChName;
            ChSettings = new Hashtable();
            Shits = new Hashtable();
            Exempts = new Hashtable();
            Reops = new Hashtable();
            Invites = new Hashtable();
            Reibs = new List<Hashtable>(4);
            Reibs.Add(Shits);
            Reibs.Add(Exempts);
            Reibs.Add(Reops);
            Reibs.Add(Invites);
        }

        public void ChSet(String ChSetting, String Value)
        {
            HashUtil.modHashtable(ChSettings, ChSetting, Value);
        }

        public void addReib(ReibType ReibT, String Hostmask)
        {
            try
            {
                Reibs[(int)ReibT].Add(Hostmask, new Reib(Hostmask, null, null, false));
            }
            catch (Exception e) { }
        }

        public void delReib(ReibType ReibT, String Hostmask)
        {
            try
            {
                Reibs[(int)ReibT].Remove(Hostmask);
            }
            catch (Exception e) { }
        }
    }

    public class Reib
    {
        private String Hostmask;
        private String Expires;
        private String Reason;
        private Boolean Sticked;

        public Reib(String Hostmask, String Expires, String Reason, Boolean Sticked)
        {
            this.Hostmask = Hostmask;
            this.Expires = Expires;
            this.Reason = Reason;
            this.Sticked = Sticked;
        }

        public String getHostmask() { return Hostmask; }

        public String getExpires() { return Expires; }

        public String getReason() { return Reason; }

        public Boolean IsSticked() { return Sticked; }

    }

    abstract public class Handle
    {
        private String handleID;
        private List<String> Hostnames;
        private String globalFlags;
        private String createdAt;
        private Boolean hasPassword;
        private Boolean isMatched;

        public Handle(String HandleID)
        {
            this.handleID = HandleID;
            this.Hostnames = new List<String>();
        }

        public void addHostname(String Hostname)
        {
            if (!Hostnames.Contains(Hostname))
                Hostnames.Add(Hostname);
        }

        public void delHostname(String Hostname)
        {
            Hostnames.Remove(Hostname);
        }

        public List<String> getHostnames() { return Hostnames; }

        protected String ParseFlags(String OldFlags, String SetFlags)
        {
            Boolean toAdd = true;
            foreach (Char c in SetFlags.ToCharArray())
            {
                switch (c)
                {
                    case '+':
                        toAdd = true;
                        break;
                    case '-':
                        toAdd = false;
                        break;
                    default:
                        if (toAdd)
                        {
                            if (OldFlags.IndexOf(c) == -1)
                                OldFlags += c;
                        }
                        else
                        {
                            OldFlags = OldFlags.Replace(c.ToString(), string.Empty);
                        }
                        break;
                }
            }
            //TODO
            return OldFlags;
        }

        public String HandleID
        {
            get { return handleID; }
            set
            {
                if (value.Length < 1)
                    throw new Exception("HandleID must be at least 1 char long");
                else
                    handleID = value;
            }
        }

        public Boolean IsMatched
        {
            get { return isMatched; }
            set { isMatched = value; }
        }

        public Boolean HasPassword
        {
            get { return hasPassword; }
            set { hasPassword = value; }
        }

        public String CreatedAt
        {
            get { return createdAt; }
            set { createdAt = value; }
        }

        public String GlobalFlags
        {
            get { return globalFlags; }
            set { globalFlags = value; }
        }

    }

    public class User : Handle
    {
        private Hashtable ChannelFlags;

        public User(String UserHandle)
            : base(UserHandle)
        {
            this.ChannelFlags = new Hashtable();
        }

        public void setChannelFlag(String Channel, String Flags)
        {
            if (ChannelFlags.ContainsKey(Channel))
                ChannelFlags[Channel] = Flags;
            else
                ChannelFlags.Add(Channel, Flags);
        }

        public void delChannelFlag(String Channel)
        {
            try
            {
                ChannelFlags.Remove(Channel);
            }
            catch (Exception e) { }
        }
    }

    public class Bot : Handle
    {
        private String ipAddess;
        private Boolean isLinked;

        public Bot(String BotHandle)
            : base(BotHandle)
        {
            GlobalFlags = "b";
        }

        public String IpAddress
        {
            get { return ipAddess; }
            set { ipAddess = value; }
        }

        public Boolean IsLinked
        {
            get { return isLinked; }
            set { isLinked = value; }
        }

    }

    internal class HashUtil
    {
        public static Boolean modHashtable(Hashtable ht, Object Key, Object Value)
        {
            if (ht.ContainsKey(Key))
            {
                ht[Key] = Value;
                return false;
            }
            else
                ht.Add(Key, Value);
            return true;
        }
    }

}
